//
//  TTOperation.m
//  Tint
//
//  Created by Kevin Wu on 2/22/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "TTOperation.h"

@interface TTOperation (Private)

- (BOOL)shouldTransitionToState:(TTOperationState)state;
+ (NSString *)keyPathFromOperationState:(TTOperationState)state;

@end




@implementation TTOperation



#pragma mark - Accessors

@synthesize error = _error;


@synthesize state = _state;

- (void)setState:(TTOperationState)state {
    
    if (![self shouldTransitionToState:state]) {
        return;
    }
    
    NSString *oldStateKey = [[self class] keyPathFromOperationState:self.state];
    NSString *newStateKey = [[self class] keyPathFromOperationState:state];
    
    [self willChangeValueForKey:newStateKey];
    [self willChangeValueForKey:oldStateKey];
    _state = state;
    [self didChangeValueForKey:oldStateKey];
    [self didChangeValueForKey:newStateKey];
}



#pragma mark - Memory

- (void)dealloc {
    TTRelease(_error);
    TTRelease(_delegates);
    [super dealloc];
}



#pragma mark - NSOperation

- (void)cancel {
    if ([self isFinished]) {
        return;
    }
    
    [self willChangeValueForKey:@"isCancelled"];
    _cancelled = YES;
    [self didChangeValueForKey:@"isCancelled"];
    
    [super cancel];
}

- (BOOL)isReady {
    return (self.state == TTOperationStateReady) && [super isReady];
}

- (BOOL)isExecuting {
    return (self.state == TTOperationStateExecuting);
}

- (BOOL)isFinished {
    return (self.state == TTOperationStateFinished) || [self isCancelled];
}

- (BOOL)isCancelled {
    return _cancelled;
}

- (BOOL)isConcurrent {
    return YES;
}



#pragma mark - Public

- (void)operationDidStart {
    [[self delegates] makeObjectsRunSelectorOnMainThread:@selector(operationDidStart:) withObject:self];
}

- (void)operationUpdated {
    [[self delegates] makeObjectsRunSelectorOnMainThread:@selector(operationUpdated:) withObject:self];
}

- (void)operationDidFailWithError:(NSError *)error {
    [[self delegates] makeObjectsRunSelectorOnMainThread:@selector(operationDidFail:withError:) withObject:self withObject:error];
}

- (void)operationWillFinish {
    [[self delegates] makeObjectsRunSelectorOnMainThread:@selector(operationWillFinish:) withObject:self];
}

- (void)operationDidFinish {
    [[self delegates] makeObjectsRunSelectorOnMainThread:@selector(operationDidFinish:) withObject:self];
}



#pragma mark - TTDelegatesProtocol

- (NSMutableArray *)delegates {
    if (_delegates == nil) {
        _delegates = [[NSMutableArray weakArray] retain];
    }
    return _delegates;
}

- (id)addDelegate:(id)delegate {
    return [[self delegates] addNonEqualObjectIfNotNil:delegate];
}

- (void)removeDelegate:(id)delegate {
    [[self delegates] removeObject:delegate];
}

- (void)removeAllDelegates {
    [[self delegates] removeAllObjects];
}

@end


@implementation TTOperation (Private)

- (BOOL)shouldTransitionToState:(TTOperationState)state {
    switch (self.state) {
        case TTOperationStateReady:
            return ((state == TTOperationStateExecuting) || (state == TTOperationStateFinished));
        case TTOperationStateExecuting:
            return (state == TTOperationStateFinished);
        case TTOperationStateFinished:
            return NO;
    }
    return YES;
}

+ (NSString *)keyPathFromOperationState:(TTOperationState)state {
    switch (state) {
        case TTOperationStateReady:
            return @"isReady";
        case TTOperationStateExecuting:
            return @"isExecuting";
        case TTOperationStateFinished:
            return @"isFinished";
    }
    return @"state";
}

@end
